﻿// See https://aka.ms/new-console-template for more information
//异步是值任务的执行不是按照固定的顺序进行的，而是根据事件的发生和处理的速度来决定的。在异步编程中，程序会在等待某些操作完成时继续执行其他任务，而不是一直等待操作完成后再执行下一个任务。
//在计算机运行过程中，CPU运行的速度往往是超过系统IO的速度。
//在实际开发过程中，经常出现这种场景，就是一个方法运行过程中需要调用查询数据中一些数据，而在同步编程中，方法运行至查询数据这一操作中需要等待数据库查询结果的返回，而这一段等待的时间，这个线程是完全空置的，因此需要异步编程来利用好这段线程空置的时间。

//并行是指的多个任务同时执行，每个任务都有自己的处理器线程。在并行编程中，程序将会分配给不同的任务处理器或线程，以便同时执行多个任务，从而提高程序的执行效率。

//因此，异步和并行虽然都是多任务处理的方式，但是他们的实现方式和应用场景是不同的。

using System.Diagnostics;

//异步执行
List<Task> tasks = new();
tasks.Add(cw1());
tasks.Add(cw2());
await Task.WhenAll(tasks);//此时任务1与任务2输出的时间应该只相差2秒，此时异步执行虽然只有一个线程，但是在遇见任务1的第一个await便返回到了调用方，继续执行其他操作

Process process = Process.GetCurrentProcess();//获取当前进程对象
var ThreadCount = process.Threads.Count;//获取当前使用的线程总数
Console.WriteLine(ThreadCount);

//并行执行
Task.Run(async () =>
{
    Process process = Process.GetCurrentProcess();//获取当前进程对象
    var ThreadCount = process.Threads.Count;//获取当前使用的线程总数
    Console.WriteLine(ThreadCount);
    await cw1();
});
//此时同时开启两个线程分别执行两个任务
//上面这句话并不绝对，因为Task是根据线程池封装而来，而其内部有复杂的算法过程来判断什么时候创建线程，什么时候使用线程池中的线程，什么时候销毁线程，因此上面这一句话并不一定会创建两个线程。
Task.Run(async () =>
{
   Process process = Process.GetCurrentProcess();//获取当前进程对象
   var ThreadCount = process.Threads.Count;//获取当前使用的线程总数
   Console.WriteLine(ThreadCount);
   await cw2();
});

Console.ReadLine();

Console.WriteLine("Hello, World!");

//Task.Delay()和Thread.Sleep()的区别
//Task.Delay()是异步的，他会创建一个延迟任务，该任务会在指定的时间后回复当前线程的执行。在等待期间，当前线程可以执行其他任务，因此，Task.Delay()不会阻塞当前线程。
//Thread.Sleep()是同步的，他会暂停当前线程的执行，指导指定的时间过去。在等待期间，当前线程无法执行其他任务，因此，Thread.Sleep()会阻塞当前线程。
//总的来说，Task.Delay()更适合异步编程中使用，而Thread.Sleep更适合在同步编程中使用。
//任务1
async Task cw1()
{
    await Task.Delay(1000);//模拟数据库查询过程，假设这个过程需要一秒,创建延迟任务，异步的
    //Thread.Sleep(1000);//阻塞线程，同步的
    Console.WriteLine(DateTime.Now);
}
//任务2
async Task cw2()
{
    await Task.Delay(3000);//模拟数据库查询过程，假设这个过程需要三秒
    Console.WriteLine(DateTime.Now);
}